//
// Created by jinbang.li on 2023/7/23.
//

#include "OpSLAudioPlay.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include "../Log/OpLog.h"

OpSLAudioPlay::OpSLAudioPlay() {
    buf = new unsigned char[1024*1024];
}
OpSLAudioPlay::~OpSLAudioPlay() {
    delete buf;
    buf = 0;
}
static SLObjectItf engineSL = NULL;
static SLEngineItf eng = NULL;
static SLObjectItf mix = NULL;
static SLObjectItf player = NULL;
static SLPlayItf iplayer = NULL;
static SLAndroidSimpleBufferQueueItf pcmQue = NULL;
static SLEngineItf CreateSL(){
    SLresult lresult = SL_RESULT_SUCCESS;
    SLEngineItf engineItf;
    lresult = slCreateEngine(&engineSL,0,0,0,0,0);
    if (lresult != SL_RESULT_SUCCESS) return NULL;
    lresult = (*engineSL)->Realize(engineSL,SL_BOOLEAN_FALSE);
    if (lresult != SL_RESULT_SUCCESS) return NULL;
    lresult = (*engineSL)->GetInterface(engineSL,SL_IID_ENGINE,&engineItf);
    if (lresult != SL_RESULT_SUCCESS) return NULL;
    return engineItf;
}
void OpSLAudioPlay::playCall(void *bufq) {
    if (!bufq)return;
    SLAndroidSimpleBufferQueueItf bufferQueueItf = (SLAndroidSimpleBufferQueueItf)bufq;
    OPLOGD("OpSLAudioPlay::playCall");
    OpData data = GetData();
    if (data.size <= 0){
        OPLOGD("GetData size is 0");
        return;
    }
    if (!buf)return;
    memcpy(buf,data.data,data.size);
    (*bufferQueueItf)->Enqueue(bufferQueueItf,buf,data.size);
    data.dropData();
}
static void pcmCall(SLAndroidSimpleBufferQueueItf bufferQueueItf,void *context){
    OpSLAudioPlay *audioPlay = (OpSLAudioPlay *)context;
    if (!audioPlay){
        OPLOGE("OpSLAudioPlay context null");
        return;
    }
    audioPlay->playCall((void *)bufferQueueItf);
}
bool OpSLAudioPlay::startPlay(OpParameter out) {
    eng = CreateSL();
    if (!eng){
        OPLOGE("createSL failed");
        return false;
    }
    SLresult result = SL_RESULT_SUCCESS;
    result = (*eng)->CreateOutputMix(eng,&mix,0,0,0);
    if (result != SL_RESULT_SUCCESS){
        OPLOGE("CreateOutputMix failed");
        return false;
    }
    result = (*mix)->Realize(mix,SL_BOOLEAN_FALSE);
    if (result != SL_RESULT_SUCCESS){
        OPLOGE("Realize failed");
        return false;
    }
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,mix};
    SLDataSink audioSink = {&outputMix,0};

    SLDataLocator_AndroidSimpleBufferQueue queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10};
    SLDataFormat_PCM pcm = {
            SL_DATAFORMAT_PCM,
            (SLuint32)out.channels,
            (SLuint32)out.sample_rate*1000,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN
    };

    SLDataSource dataSource = {&queue,&pcm};

    const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[] = {SL_BOOLEAN_TRUE};
    result = (*eng)->CreateAudioPlayer(eng,&player,&dataSource,&audioSink, sizeof(ids)/ sizeof(SLInterfaceID),ids,req);
    if (result != SL_RESULT_SUCCESS){
        OPLOGE("CreateAudioPlayer failed!");
        return false;
    }
    (*player)->Realize(player,SL_BOOLEAN_FALSE);
    result = (*player)->GetInterface(player,SL_IID_PLAY,&iplayer);
    if (result != SL_RESULT_SUCCESS){
        OPLOGE("GetInterface SL_IID_PLAY failed!");
        return false;
    }
    result = (*player)->GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);
    if (result != SL_RESULT_SUCCESS){
        OPLOGE("GetInterface SL_IID_BUFFERQUEUE failed!");
        return false;
    }
    (*pcmQue)->RegisterCallback(pcmQue, pcmCall, this);
    (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING);
    (*pcmQue)->Enqueue(pcmQue,"",1);
    OPLOGD("startPlay success");
    return true;
}
